/*
 *  logic.cpp
 *  
 *  Created by James Dykstra
 *	Team 5
 *
 *  Copyright 2010 Michigan Technological University. All rights reserved.
 */
#include "logic.h"
#include "sprite.h"

Logic::Logic(Renderer *rnd, Map* m)
{
	renderer = rnd;
	map = m;
}
Logic::~Logic()
{
}
bool Logic::checkCollide(Sprite *spr1, Sprite *spr2)
{
	std::fstream debug("log.txt", std::fstream::out | std::fstream::app);
	debug<<"Attempting collision tests.\n";
	debug.close();
	if(spr1!=0 && spr2!=0 && spr1->getHitbox()!=0 && spr2->getHitbox()!=0)
	{
		std::fstream debug("log.txt", std::fstream::out | std::fstream::app);
		debug<<"Passed basic spr1, spr2 and hitbox validity checks.\n";
		debug.close();
		Vector *AVectors[4];
		Vector *tmp = spr1->getSizeVector();
		float snA = sin(spr1->getAngle());
		float csA = cos(spr1->getAngle());
		//tmp->rotateVector(snA, csA);
		
		AVectors[UR] = spr1->getCenterVector();
		AVectors[UR]->setX(AVectors[0]->getX()+(tmp->getX()/2));
		AVectors[UR]->setY(AVectors[0]->getY()-(tmp->getY()/2));
		AVectors[UR]->rotateVector(csA, snA);
		AVectors[UL] = spr1->getCenterVector();
		AVectors[UL]->setX(AVectors[1]->getX()-(tmp->getX()/2));
		AVectors[UL]->setY(AVectors[1]->getY()-(tmp->getY()/2));
		AVectors[UL]->rotateVector(csA, snA);
		AVectors[LL] = spr1->getCenterVector();
		AVectors[LL]->setX(AVectors[2]->getX()-(tmp->getX()/2));
		AVectors[LL]->setY(AVectors[2]->getY()+(tmp->getY()/2));
		AVectors[LL]->rotateVector(csA, snA);
		AVectors[LR] = spr1->getCenterVector();
		AVectors[LR]->setX(AVectors[3]->getX()+(tmp->getX()/2));
		AVectors[LR]->setY(AVectors[3]->getY()+(tmp->getY()/2));
		AVectors[LR]->rotateVector(csA, snA);
		delete tmp;
		
		Vector *BVectors[4];
		tmp = spr2->getSizeVector();
		float snB = sin(spr2->getAngle());
		float csB = cos(spr2->getAngle());
		
		BVectors[UR] = spr2->getCenterVector();
		BVectors[UR]->setX(BVectors[0]->getX()+(tmp->getX()/2));
		BVectors[UR]->setY(BVectors[0]->getY()-(tmp->getY()/2));
		BVectors[UR]->rotateVector(csB, snB);
		BVectors[UL] = spr2->getCenterVector();
		BVectors[UL]->setX(BVectors[1]->getX()-(tmp->getX()/2));
		BVectors[UL]->setY(BVectors[1]->getY()-(tmp->getY()/2));
		BVectors[UL]->rotateVector(csB, snB);
		BVectors[LL] = spr2->getCenterVector();
		BVectors[LL]->setX(BVectors[2]->getX()-(tmp->getX()/2));
		BVectors[LL]->setY(BVectors[2]->getY()+(tmp->getY()/2));
		BVectors[LL]->rotateVector(csB, snB);
		BVectors[LR] = spr2->getCenterVector();
		BVectors[LR]->setX(BVectors[3]->getX()+(tmp->getX()/2));
		BVectors[LR]->setY(BVectors[3]->getY()+(tmp->getY()/2));
		BVectors[LR]->rotateVector(csB, snB);
		delete tmp;
		
		Vector AAxis[2];
		Vector BAxis[2];
		
		AAxis[0].setX(AVectors[UR]->getX() - AVectors[UL]->getX());
		AAxis[0].setY(AVectors[UR]->getY() - AVectors[UL]->getY());
		AAxis[1].setX(AVectors[UR]->getX() - AVectors[LR]->getX());
		AAxis[1].setY(AVectors[UR]->getY() - AVectors[LR]->getY());

		BAxis[0].setX(BVectors[UL]->getX() - BVectors[LL]->getX());
		BAxis[0].setY(BVectors[UL]->getY() - BVectors[LL]->getY());
		BAxis[1].setX(BVectors[UL]->getX() - BVectors[UR]->getX());
		BAxis[1].setY(BVectors[UL]->getY() - BVectors[UR]->getY());

		Vector ProjA[4];
		Vector ProjB[4];

		for(int i=0; i<2; i++)
		{
			ProjA[UR].setX(((AVectors[UR]->getX() * AAxis[i].getX() + AVectors[UR]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getX());
			ProjA[UR].setY(((AVectors[UR]->getX() * AAxis[i].getX() + AVectors[UR]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getY());
			ProjA[UL].setX(((AVectors[UL]->getX() * AAxis[i].getX() + AVectors[UL]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getX());
			ProjA[UL].setY(((AVectors[UL]->getX() * AAxis[i].getX() + AVectors[UL]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getY());
			ProjA[LL].setX(((AVectors[LL]->getX() * AAxis[i].getX() + AVectors[LL]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getX());
			ProjA[LL].setY(((AVectors[LL]->getX() * AAxis[i].getX() + AVectors[LL]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getY());
			ProjA[LR].setX(((AVectors[LR]->getX() * AAxis[i].getX() + AVectors[LR]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getX());
			ProjA[LR].setY(((AVectors[LR]->getX() * AAxis[i].getX() + AVectors[LR]->getY() * AAxis[i].getY())/((AAxis[i].getX()*AAxis[i].getX())+(AAxis[i].getY()*AAxis[i].getY())))*AAxis[i].getY());


			ProjB[UR].setX(((BVectors[UR]->getX() * BAxis[i].getX() + BVectors[UR]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getX());
			ProjB[UR].setY(((BVectors[UR]->getX() * BAxis[i].getX() + BVectors[UR]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getY());
			ProjB[UL].setX(((BVectors[UL]->getX() * BAxis[i].getX() + BVectors[UL]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getX());
			ProjB[UL].setY(((BVectors[UL]->getX() * BAxis[i].getX() + BVectors[UL]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getY());
			ProjB[LL].setX(((BVectors[LL]->getX() * BAxis[i].getX() + BVectors[LL]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getX());
			ProjB[LL].setY(((BVectors[LL]->getX() * BAxis[i].getX() + BVectors[LL]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getY());
			ProjB[LR].setX(((BVectors[LR]->getX() * BAxis[i].getX() + BVectors[LR]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getX());
			ProjB[LR].setY(((BVectors[LR]->getX() * BAxis[i].getX() + BVectors[LR]->getY() * BAxis[i].getY())/((BAxis[i].getX()*BAxis[i].getX())+(BAxis[i].getY()*BAxis[i].getY())))*BAxis[i].getY());

				
			float AScalars[4];
			float BScalars[4];	
			
			for(int a=0; a<4; a++)
			{
				AScalars[a] = ProjA[a].getX() * AAxis[i].getX() + ProjA[a].getY() * AAxis[i].getY();
				BScalars[a] = ProjB[a].getX() * BAxis[i].getX() + ProjB[a].getY() * BAxis[i].getY();
			}

			float minA = min(AScalars);
			float maxA = max(AScalars);
			float minB = min(BScalars);
			float maxB = max(BScalars);

			std::fstream debug("log.txt", std::fstream::out | std::fstream::app);
			debug<<"minA: "<<minA<<std::endl;
			debug<<"maxA: "<<maxA<<std::endl;
			debug<<"minB: "<<minB<<std::endl;
			debug<<"maxB: "<<maxB<<std::endl;
			debug.close();

			if((minB <= maxA) || (maxB >= minA))
			{
			//overlap exists with this axis
			//do nothing
			}
			else
			{
				for(int c=0; c<4; c++)
				{
					delete AVectors[c];
					delete BVectors[c];
				}
				return false;
			}
		}
		for(int c=0; c<4; c++)
		{
			delete AVectors[c];
			delete BVectors[c];
		}
		return true;
	}
	else
		return false;
}

bool Logic::validMove(Sprite * sprite, int xOffset, int yOffset, float angle)
{
	bool returnValue = true;
	sprite->getRect()->x += xOffset;
	sprite->getRect()->y += yOffset;
	sprite->setAngle((sprite->getAngle()+angle));
	do {
		if(((sprite->getRect()->x + sprite->getRect()->w) > map->getMapWidth()) || (sprite->getRect()->x < 0)) {
			returnValue=false;
			break;
		}
		
		if(((sprite->getRect()->y + sprite->getRect()->h) > map->getMapHeight()) || (sprite->getRect()->y < 0)) {
			returnValue=false;
			break;
		}
		
		for (int i=0; i<map->getNumObstacles(); i++) {
			if (checkCollide(sprite, map->getObstacle(i))) {
				returnValue = false;
				break;
			}
		}
	} while (false);
	
	sprite->getRect()->x -= xOffset;
	sprite->getRect()->y -= yOffset;
	sprite->setAngle((sprite->getAngle()-angle));
	
	return returnValue;
}
float Logic::min(float scalars[4])
{
	float mn = scalars[0];
	for(int i=1; i<4; i++)
	{
		if(scalars[i]<mn)
			mn = scalars[i];
	}
	return mn;
}
float Logic::max(float scalars[4])
{
	float mx = scalars[0];
	for(int i=1; i<4; i++)
	{
		if(scalars[i]>mx)
			mx = scalars[i];
	}
	return mx;
}
